package io.gitee.thghh.dynamic.liquibase.liquibase;

import io.gitee.thghh.dynamic.liquibase.property.DynamicProperty;
import liquibase.ContextExpression;
import liquibase.Contexts;
import liquibase.LabelExpression;
import liquibase.Labels;
import liquibase.Liquibase;
import liquibase.changelog.ChangeLogParameters;
import liquibase.changelog.DatabaseChangeLog;
import liquibase.changelog.visitor.ChangeExecListener;
import liquibase.changelog.visitor.DefaultChangeExecListener;
import liquibase.database.Database;
import liquibase.exception.DatabaseException;
import liquibase.exception.LiquibaseException;
import liquibase.integration.spring.SpringLiquibase;
import liquibase.integration.spring.SpringResourceAccessor;
import liquibase.resource.ResourceAccessor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.DisposableBean;

import javax.sql.DataSource;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;

/**
 * 动态Spring Liquibase
 *
 * @author pengzhikang
 * @date 2024/11/28 19:57
 * @since 1.0.0
 */
public class DynamicSpringLiquibase extends SpringLiquibase implements DisposableBean {

    /** 监听器 */
    private final List<ChangeExecListener> listeners = new ArrayList<>(6);

    /** 动态属性 */
    private final List<DynamicProperty> dynamicPropertys = new ArrayList<>(6);

    public DynamicSpringLiquibase() {
        super();
    }

    @Override
    public Liquibase createLiquibase(Connection c) throws LiquibaseException {
        Liquibase liquibase = super.createLiquibase(c);

        // 添加监听
        addListener(liquibase);
        // 添加动态属性
        addDynamicPropertys(liquibase);
        return liquibase;
    }

    /**
     * 添加监听器
     *
     * @param liquibase liquibase
     * @author pengzhikang
     * @date 2025/02/11 10:57
     */
    private void addListener(Liquibase liquibase) {
        DefaultChangeExecListener defaultChangeExecListener = liquibase.getDefaultChangeExecListener();
        listeners.forEach(defaultChangeExecListener::addListener);
        liquibase.setChangeExecListener(defaultChangeExecListener);
    }

    /**
     * 添加动态属性
     *
     * @param liquibase liquibase
     * @author pengzhikang
     * @date 2025/02/11 10:27
     */
    private void addDynamicPropertys(Liquibase liquibase) {
        ChangeLogParameters changeLogParameters = liquibase.getChangeLogParameters();
        for (DynamicProperty dynamicProperty : dynamicPropertys) {
            changeLogParameters.set(dynamicProperty.getName(), dynamicProperty, null, (String) null, dynamicProperty.getDbms(), true, null);
        }
    }

    @Override
    public Database createDatabase(Connection c, ResourceAccessor resourceAccessor) throws DatabaseException {
        return super.createDatabase(c, resourceAccessor);
    }

    @Override
    public SpringResourceAccessor createResourceOpener() {
        return super.createResourceOpener();
    }

    /**
     * 回滚到指定标签
     *
     * @param tag 标签
     * @return boolean 是否成功
     * @throws LiquibaseException 异常
     * @author pengzhikang
     * @date 2024/11/28 20:24
     */
    public boolean rollback(String tag) throws LiquibaseException {
        Liquibase liquibase = null;
        try {
            final Connection c = getDataSource().getConnection();
            liquibase = createLiquibase(c);
            if (liquibase.tagExists(tag)) {
                liquibase.rollback(tag, null, new Contexts(getContexts()), new LabelExpression());
            } else {
                return false;
            }
        } catch (Exception e) {
            throw new DatabaseException(e);
        } finally {
            if (liquibase != null) {
                liquibase.close();
            }
        }

        return true;
    }

    @Override
    public void destroy() {
        DataSource dataSource = getDataSource();
        if (dataSource instanceof AutoCloseable) {
            AutoCloseable c = (AutoCloseable) dataSource;
            try {
                c.close();
            } catch (Exception ignored) {
            }
        }
    }

    /**
     * 添加监听
     * @param listener
     * @author pengzhikang
     * @date 2024/12/03
     */
    public void addListener(ChangeExecListener listener) {
        if (listener != null) {
            this.listeners.add(listener);
        }
    }

    /**
     * 添加监听
     * @param listeners
     * @author pengzhikang
     * @date 2024/12/03
     */
    public void addListeners(List<ChangeExecListener> listeners) {
        if (listeners != null) {
            this.listeners.addAll(listeners);
        }
    }

    /**
     * 添加动态特性
     *
     * @param dynamicProperty 动态特性
     * @author pengzhikang
     * @date 2025/02/11 10:34
     */
    public void addDynamicPropertie(DynamicProperty dynamicProperty) {
        if (dynamicProperty != null) {
            this.dynamicPropertys.add(dynamicProperty);
        }
    }

    /**
     * 添加动态属性
     *
     * @param dynamicPropertys 动态属性
     * @author pengzhikang
     * @date 2025/02/11 10:34
     */
    public void addDynamicProperties(List<DynamicProperty> dynamicPropertys) {
        if (dynamicPropertys != null) {
            this.dynamicPropertys.addAll(dynamicPropertys);
        }
    }

    @Override
    public String toString() {
        return getClass().getName() + "(" + beanName + ")";
    }
}
